package com.tengju.bff.interfaces.covercharge.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.idanchuang.component.config.apollo.util.ConfigUtil;
import com.tengju.bff.interfaces.covercharge.constant.*;
import com.tengju.bff.interfaces.covercharge.dto.BankInfo;
import com.tengju.bff.interfaces.covercharge.dto.SelfCertificationDto;
import com.tengju.bff.interfaces.covercharge.dto.WithdrawalModify;
import com.tengju.bff.interfaces.covercharge.entity.dto.RegisteredInfo;
import com.tengju.bff.interfaces.covercharge.entity.dto.ServiceLetaxRegisteredDto;
import com.tengju.bff.interfaces.covercharge.entity.dto.WithdrawalApplyInfo;
import com.tengju.bff.interfaces.covercharge.entity.dto.WithdrawalRule;
import com.tengju.bff.interfaces.covercharge.entity.po.*;
import com.tengju.bff.interfaces.covercharge.entity.vo.WithdrawalApply;
import com.tengju.bff.interfaces.covercharge.entity.vo.WithdrawalApplyBeforeResult;
import com.tengju.bff.interfaces.covercharge.entity.vo.WithdrawalApplyInfoResult;
import com.tengju.bff.interfaces.covercharge.enums.ProfitTypeEnum;
import com.tengju.bff.interfaces.covercharge.intf.INoticeMemberProvider;
import com.tengju.bff.interfaces.covercharge.intf.IWithdrawalProvider;
import com.tengju.bff.interfaces.covercharge.mapper.ServiceBankMapper;
import com.tengju.bff.interfaces.covercharge.mapper.ServiceLetaxRegisteredMapper;
import com.tengju.bff.interfaces.covercharge.service.*;
import com.tengju.bff.interfaces.covercharge.service.message.client.UserMessageClient;
import com.tengju.bff.interfaces.covercharge.util.DateTimeUtils;
import com.tengju.bff.interfaces.covercharge.util.MoneyHelper;
import com.tengju.bff.interfaces.covercharge.util.MoneyUtils;
import com.tengju.payment.application.shard.ApplicationException;
import com.tengju.payment.application.shard.ApplicationExceptionCode;
import com.tengju.settlement.domain.model.account.UserIdCode;
import com.tengju.settlement.domain.model.depository.*;
import com.tengju.user.application.user.UserInfoService;
import com.tengju.user.domain.model.archive.IdCardNo;
import com.tengju.user.domain.model.archive.letax.*;
import com.tengju.user.domain.model.archive.resume.BankCard;
import com.tengju.user.domain.model.archive.resume.BankCardRepository;
import com.tengju.user.domain.model.archive.resume.BankCardStatus;
import com.tengju.user.domain.model.archive.sign.Sign;
import com.tengju.user.domain.model.archive.sign.SignLog;
import com.tengju.user.domain.model.archive.sign.SignLogRepository;
import com.tengju.user.domain.model.archive.sign.SignRepository;
import com.tengju.user.domain.shared.AccountId;
import com.tengju.user.domain.shared.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.tengju.user.domain.model.archive.letax.IdentityType.*;
import static com.tengju.user.domain.model.archive.letax.LetaxStatus.UN_APPLY;

/**
 * <p>
 * 乐税个体户服务实现类
 * </p>
 *
 * @author zhaoyi
 * @since 2020-02-24
 */
@Service
@Slf4j
public class LeTaxOneServiceImpl implements LeTaxOneService {

    @Autowired
    private IServiceAccountService serviceAccountService;

    @Autowired
    private IServiceSignService serviceSignService;

    @Autowired
    private IServiceWithdarwCycleAddService serviceWithdarwCycleAddService;

    @Autowired
    private IServiceLetaxRegisteredService serviceLetaxRegisteredService;

    @Autowired
    private IServiceLetaxWithdrawLogService serviceLetaxWithdrawLogService;

    @Autowired
    private ServiceBankMapper serviceBankMapper;

    @Autowired
    private ServiceLetaxRegisteredMapper serviceLetaxRegisteredMapper;

    @Autowired
    private UserMessageClient userMessageClient;

    @Autowired
    private SelfCertificationServiceImpl selfCertificationServiceImpl;

    @Autowired
    private IServiceSelfCertificationWithdrawService serviceSelfCertificationWithdrawService;

    @Autowired
    private INoticeMemberProvider noticeMemberProvider;

    @Autowired
    @Lazy
    private IWithdrawalProvider withdrawalProvider;

    @Autowired
    private DepositoryAccountRepository depositoryAccountRepository;

    @Autowired
    private DepositoryBankCardRepository depositoryBankCardRepository;

    private final LetaxRepository letaxRepository;

    private final LetaxWithdrawRepository letaxWithdrawRepository;

    private final LetaxSnapshotRepository letaxSnapshotRepository;

    private final SignRepository signRepository;

    private final SignLogRepository signLogRepository;

    private final BankCardRepository bankCardRepository;
    private final UserInfoService userInfoService;


    @Value("${depository.account.whiteList}")
    private String DepAccountWhiteList;


    public LeTaxOneServiceImpl(LetaxRepository letaxRepository,
                               LetaxWithdrawRepository letaxWithdrawRepository,
                               LetaxSnapshotRepository letaxSnapshotRepository,
                               SignRepository signRepository,
                               SignLogRepository signLogRepository,
                               BankCardRepository bankCardRepository,
                               UserInfoService userInfoService) {
        this.letaxRepository = letaxRepository;
        this.letaxWithdrawRepository = letaxWithdrawRepository;
        this.letaxSnapshotRepository = letaxSnapshotRepository;
        this.signRepository = signRepository;
        this.signLogRepository = signLogRepository;
        this.bankCardRepository = bankCardRepository;
        this.userInfoService = userInfoService;
    }

    /**
     * 查询个体申请前信息
     *
     * @param accountType 账户类型
     * @param idCode      idCodez
     */
    @Override
    public WithdrawalApplyBeforeResult queryWithdrawalApplyBefore(
            CoverChargeEnum.ServiceAccountType accountType, Integer idCode) {
        ServiceSign serviceSignParam = new ServiceSign();
        serviceSignParam.setIdCode(idCode);
        serviceSignParam.setPlatformCode(accountType.getPlatform());
        ServiceSign serviceSign = serviceSignService.getOne(new QueryWrapper<>(serviceSignParam));
        // 判断是否签约
        Assert.isTrue(serviceSign != null && CoverChargeEnum.CommonStatus.YES.getName()
                .equals(serviceSign.getIsSigned()), "未签约");
        Assert.isTrue(SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.regist_soho.toString().equals(serviceSign.getCurrentIdentity()),
                "当前身份不正确");

        ServiceAccount serviceAccount = serviceAccountService
                .getAccount(accountType.getCode(), idCode);

        // 超过提现上限的判断
        Integer accountId = serviceAccount.getId();

        WithdrawalApplyBeforeResult withdrawalApplyBeforeResult = new WithdrawalApplyBeforeResult();
        withdrawalApplyBeforeResult.setLimitMoney(
                SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity()) ?
                        new BigDecimal(ConfigUtil.getConfig().getString("person.limit", "0")) :
                        new BigDecimal(ConfigUtil.getConfig().getString("regist-soho.limit", "0")));

        //当前时间
        Date nowDate = new Date();
        BigDecimal cycleTotalMoney = this
                .getTotalCycleMoney(nowDate, serviceSign.getCurrentIdentity(), accountId, idCode);
        if (cycleTotalMoney.compareTo(BigDecimal.ZERO) == 0) {
            withdrawalApplyBeforeResult.setCanApplyMoney(serviceAccount.getBalance()
                    .compareTo(withdrawalApplyBeforeResult.getLimitMoney()) < 0
                    ? serviceAccount.getBalance() : withdrawalApplyBeforeResult.getLimitMoney());
        } else {
            if (cycleTotalMoney.compareTo(withdrawalApplyBeforeResult.getLimitMoney()) < 0) {
                //没有超过限额
                BigDecimal subMoney = withdrawalApplyBeforeResult.getLimitMoney()
                        .subtract(cycleTotalMoney);
                withdrawalApplyBeforeResult.setCanApplyMoney(
                        subMoney.compareTo(serviceAccount.getBalance()) < 0 ? subMoney
                                : serviceAccount.getBalance());
            } else {
                //超过限额则为0
                withdrawalApplyBeforeResult.setCanApplyMoney(BigDecimal.ZERO);
            }
        }

        String cycleDay = ConfigUtil.getConfig().getString("withdraw.cycle.day", "10");
        withdrawalApplyBeforeResult.setCycleDay(cycleDay);
        List<WithdrawalRule> withdrawalRuleList = new ArrayList<>();
        withdrawalRuleList.add(new WithdrawalRule(ConditionOperator.le.getDesc(), "15万", "4%"));
        withdrawalRuleList.add(new WithdrawalRule(ConditionOperator.gt.getDesc(), "15万", "7%"));
        withdrawalApplyBeforeResult.setRuleList(withdrawalRuleList);
        return withdrawalApplyBeforeResult;
    }

    /**
     * 获取周期内的申请金额
     *
     * @param currentIdentity 当前身份
     * @param accountId       账户ID
     * @param idCode          代理编号
     */
    private BigDecimal getTotalCycleMoney(Date nowDate, String currentIdentity, Integer accountId,
                                          Integer idCode) {
        BigDecimal totalAmount = BigDecimal.ZERO;
        if (SignIdentityEnum.regist_soho.toString().equals(currentIdentity)) {
            List<ServiceLetaxRegisteredDto> serviceLetaxRegisteredDtoList = new ArrayList<>();
            serviceLetaxRegisteredDtoList.add(new ServiceLetaxRegisteredDto(idCode));
            Map<Integer, Boolean> numberCommonMap = serviceLetaxRegisteredService
                    .getNumberCommon(serviceLetaxRegisteredDtoList);
            if (numberCommonMap.containsKey(idCode) && numberCommonMap.get(idCode)) {
                //注册个体户需要查所有的平台（身份是注册个体户的）
                ServiceSign serviceSignParam = new ServiceSign();
                serviceSignParam.setIdCode(idCode);
                serviceSignParam.setCurrentIdentity(currentIdentity);
                List<ServiceSign> serviceSignList = serviceSignService
                        .list(new QueryWrapper<>(serviceSignParam));
                for (ServiceSign serviceSign : serviceSignList) {
                    CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType
                            .getServiceAccountTypeByPlatform(serviceSign.getPlatformCode());
                    if (accountType == null) {
                        throw new RuntimeException("平台编号：" + serviceSign.getPlatformCode() + "不正确");
                    }
                    ServiceAccount serviceAccount = serviceAccountService
                            .getAccount(accountType.getCode(), idCode);
                    ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                            .getOne(new QueryWrapper<>(
                                    this.getWithdrawCycleAddParam(nowDate, serviceAccount.getId(),
                                            idCode, false)));
                    if (withdrawCycleAddResult != null) {
                        totalAmount = totalAmount.add(withdrawCycleAddResult.getTotal());
                    }
                }
            } else {
                ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                        .getOne(new QueryWrapper<>(
                                this.getWithdrawCycleAddParam(nowDate, accountId, idCode, false)));
                if (withdrawCycleAddResult != null) {
                    totalAmount = totalAmount.add(withdrawCycleAddResult.getTotal());
                }
            }
        } else {
            ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                    .getOne(new QueryWrapper<>(
                            this.getWithdrawCycleAddParam(nowDate, accountId, idCode, false)));
            if (withdrawCycleAddResult != null) {
                totalAmount = totalAmount.add(withdrawCycleAddResult.getTotal());
            }
        }

        return totalAmount;
    }

    /**
     * 查询个体申请信息
     *
     * @param accountType 账户类型
     * @param idCode      idCode
     * @param amount      申请金额
     */
    @Override
    public WithdrawalApplyInfoResult queryWithdrawalApplyInfo(
            CoverChargeEnum.ServiceAccountType accountType, Integer idCode, BigDecimal amount) {
        ServiceAccount serviceAccount = serviceAccountService
                .getAccount(accountType.getCode(), idCode);
        Integer accountId = serviceAccount.getId();

        ServiceSign serviceSignParam = new ServiceSign();
        serviceSignParam.setIdCode(idCode);
        serviceSignParam.setPlatformCode(accountType.getPlatform());
        ServiceSign serviceSign = serviceSignService.getOne(new QueryWrapper<>(serviceSignParam));
        // 判断是否签约
        Assert.isTrue(serviceSign != null && CoverChargeEnum.CommonStatus.YES.getName()
                .equals(serviceSign.getIsSigned()), "未签约");
        Assert.isTrue(SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.regist_soho.toString().equals(serviceSign.getCurrentIdentity()),
                "当前身份不正确");

        //当前时间
        Date nowDate = new Date();
        ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                .getOne(new QueryWrapper<>(
                        this.getWithdrawCycleAddParam(nowDate, accountId, idCode, false)));

        BigDecimal cycleTotalMoney =
                withdrawCycleAddResult != null ? withdrawCycleAddResult.getTotal()
                        : BigDecimal.ZERO;

        WithdrawalApplyInfoResult withdrawalApplyInfoResult = new WithdrawalApplyInfoResult();
        withdrawalApplyInfoResult.setMoney(amount);

        BigDecimal totalCycleMoney = this
                .getTotalCycleMoney(nowDate, serviceSign.getCurrentIdentity(), accountId, idCode);
        BigDecimal total = totalCycleMoney.add(amount);

        if (cycleTotalMoney.compareTo(BigDecimal.ZERO) > 0) {
            withdrawalApplyInfoResult.setCycleMoney(cycleTotalMoney.add(amount));
        } else {
            withdrawalApplyInfoResult.setCycleMoney(amount);
        }

        withdrawalApplyInfoResult.setRatio(MoneyUtils.sumRatio(total));
        withdrawalApplyInfoResult.setRatioStr(
                withdrawalApplyInfoResult.getRatio().multiply(new BigDecimal(100)) + "%");

        withdrawalApplyInfoResult.setTotalCycleMoney(total);
        withdrawalApplyInfoResult.setFee(withdrawalApplyInfoResult.getCycleMoney()
                .multiply(withdrawalApplyInfoResult.getRatio()));
        withdrawalApplyInfoResult.setFinalMoney(withdrawalApplyInfoResult.getCycleMoney()
                .subtract(withdrawalApplyInfoResult.getFee()));

        Calendar calendarNow = Calendar.getInstance();
        calendarNow.setTime(nowDate);
        int nowDay = calendarNow.get(Calendar.DAY_OF_MONTH);
        int cycleDay = Integer
                .parseInt(ConfigUtil.getConfig().getString("withdraw.cycle.day", "12"));

        if (nowDay > cycleDay) {
            calendarNow.set(Calendar.DAY_OF_MONTH, cycleDay);
            withdrawalApplyInfoResult.setEndTime(DateTimeUtils.parseDateAsString(
                    DateTimeUtils.addMonths(DateTimeUtils.addDays(calendarNow.getTime(), 3), 1),
                    "M月d号"));
        } else {
            calendarNow.set(Calendar.DAY_OF_MONTH, cycleDay);
            withdrawalApplyInfoResult.setEndTime(DateTimeUtils.parseDateAsString(
                    DateTimeUtils.addDays(calendarNow.getTime(), 3), "M月d号"));
        }
        return withdrawalApplyInfoResult;
    }

    public static void main(String[] args) {
        Calendar calendarNow = Calendar.getInstance();
        Date nowDate = new Date();
        calendarNow.setTime(nowDate);
        int nowDay = calendarNow.get(Calendar.DAY_OF_MONTH);
        int cycleDay = 12;

        if (nowDay > cycleDay) {
            calendarNow.set(Calendar.DAY_OF_MONTH, cycleDay);
            System.out.println(DateTimeUtils.parseDateAsString(
                    DateTimeUtils.addMonths(DateTimeUtils.addDays(calendarNow.getTime(), 3), 1),
                    "M月d号"));
        } else {
            calendarNow.set(Calendar.DAY_OF_MONTH, cycleDay);
            System.out.println(DateTimeUtils.parseDateAsString(
                    DateTimeUtils.addDays(calendarNow.getTime(), 3), "M月d号"));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer withdrawalApply(CoverChargeEnum.ServiceAccountType accountType, Integer idCode,
                                   WithdrawalApply withdrawalApply, DepositoryAccount depositoryAccount) {
        ServiceSign serviceSignParam = new ServiceSign();
        serviceSignParam.setIdCode(idCode);
        serviceSignParam.setPlatformCode(accountType.getPlatform());
        ServiceSign serviceSign = serviceSignService.getOne(new QueryWrapper<>(serviceSignParam));
        // 判断是否签约
        Assert.isTrue(serviceSign != null && CoverChargeEnum.CommonStatus.YES.getName()
                .equals(serviceSign.getIsSigned()), "未签约");
        Assert.isTrue(SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.regist_soho.toString().equals(serviceSign.getCurrentIdentity()),
                "当前身份不正确");

        ServiceAccount serviceAccount = serviceAccountService
                .getAccount(accountType.getCode(), idCode);

        BigDecimal balance =
                serviceAccount.getBalance() != null ? serviceAccount.getBalance() : BigDecimal.ZERO;
        BigDecimal money = withdrawalApply.getMoney();//申请金额
        Assert.isTrue(money.compareTo(balance) <= 0, "申请金额不能大于账户余额");

        // 超过提现上限的判断
        Integer accountId = serviceAccount.getId();
        //当前时间
        Date nowDate = new Date();
        BigDecimal cycleTotalMoney = this
                .getTotalCycleMoney(nowDate, serviceSign.getCurrentIdentity(), accountId, idCode);

        if (cycleTotalMoney.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal limitMoney = BigDecimal.ZERO;
            if (SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())) {
                limitMoney = new BigDecimal(ConfigUtil.getConfig().getString("person.limit", "0"));
            } else if (SignIdentityEnum.regist_soho.toString()
                    .equals(serviceSign.getCurrentIdentity())) {
                limitMoney = new BigDecimal(
                        ConfigUtil.getConfig().getString("regist-soho.limit", "0"));
            }
            Assert.isTrue(money.add(cycleTotalMoney).compareTo(limitMoney) <= 0, "周期内申请金额已超过上限");
        }

        String registeredInfo = null;
        String bankNo = "";
        if (SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())) {
            //默认银行卡提现
            BankInfo bankInfo = serviceBankMapper
                    .queryBankInfo(idCode, accountId, accountType.getPlatform());
            bankNo = bankInfo.getBankNo();
            Assert.notNull(bankInfo, "没有查询到启用状态的银行卡信息");
            registeredInfo = JSON
                    .toJSONStringWithDateFormat(bankInfo, DateTimeUtils.DEFAULT_DATE_TIME_FORMAT,
                            SerializerFeature.WriteDateUseDateFormat,
                            SerializerFeature.BrowserCompatible);
        } else if (SignIdentityEnum.regist_soho.toString()
                .equals(serviceSign.getCurrentIdentity())) {
            QueryWrapper<ServiceLetaxRegistered> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id_code", idCode);
            queryWrapper.eq("account_id", accountId);
            queryWrapper.ne("status", CoverChargeEnum.AuthStatus.END.getCode());
            //查找乐税信息
//            ServiceLetaxRegistered serviceLetaxRegistered = serviceLetaxRegisteredService
//                    .getOne(queryWrapper);
//            bankNo = serviceLetaxRegistered.getBankNo();
//            Assert.notNull(serviceLetaxRegistered, "没有查询到乐税信息");
//            Assert.isTrue(CoverChargeEnum.AuthStatus.PASS.getCode()
//                    .equals(serviceLetaxRegistered.getStatus()), "乐税状态不正确");
            List<DepositoryBankCard> depositoryBankCards = depositoryBankCardRepository
                    .getByDepositoryAccountIdStatus(new UserIdCode(idCode), depositoryAccount.getDepositoryAccountId(), List.of(BindStatus.SUCCESS));
            if (CollectionUtils.isEmpty(depositoryBankCards)) {
                throw ApplicationException.error(ApplicationExceptionCode.DEP_BAND_CARD_NOT_BOUND);
            }
            bankNo = depositoryBankCards.get(0).getCardNo();
            registeredInfo = this.getRegisteredInfo(idCode, accountId);
        }

        //如果周期表不存在记录则初始化
        ServiceWithdarwCycleAdd withdarwCycleAddParam = this
                .getWithdrawCycleAddParam(nowDate, accountId, idCode, false);
        ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                .getOne(new QueryWrapper<>(withdarwCycleAddParam));

        List<ServiceLetaxRegisteredDto> serviceLetaxRegisteredDtoList = new ArrayList<>();
        serviceLetaxRegisteredDtoList.add(new ServiceLetaxRegisteredDto(idCode));
        Map<Integer, Boolean> numberCommonMap = serviceLetaxRegisteredService
                .getNumberCommon(serviceLetaxRegisteredDtoList);

        BigDecimal totalMoney = BigDecimal.ZERO;
        if (withdrawCycleAddResult != null) {
            Assert.isTrue(CoverChargeEnum.CommonStatus.NO.getCode()
                    .equals(withdrawCycleAddResult.getWithdrawStatus()), "周期内已打款");
            if (numberCommonMap.containsKey(idCode) && numberCommonMap.get(idCode)) {
                totalMoney = cycleTotalMoney.add(money).add(withdrawCycleAddResult.getTotal());
            }
        } else {
            //如果周期表为空-且是个体工商户-同一个人申请累计金额超过10万，说明另外个平台的利率也需要修改
            if (numberCommonMap.containsKey(idCode) && numberCommonMap.get(idCode)) {
                totalMoney = cycleTotalMoney.add(money);
            }
        }
        //是否更新另一个平台的利率
        boolean needUpdateOthers = false;

        if (totalMoney.compareTo(MoneyHelper.getInstance().getServiceFeeRatioLimit()) > 0) {
            needUpdateOthers = true;
        }

        Integer cycleAddId = this
                .insertOrUpdateCycleAdd(nowDate, withdrawCycleAddResult, cycleTotalMoney, accountId,
                        idCode, withdrawalApply.getMoney(), needUpdateOthers);

        ServiceLetaxWithdrawLog serviceLetaxWithdrawLog = new ServiceLetaxWithdrawLog();
        serviceLetaxWithdrawLog.setIdCode(idCode);
        serviceLetaxWithdrawLog.setAccountId(accountId);
        serviceLetaxWithdrawLog.setCycleAddId(cycleAddId);
        //平台编号
        serviceLetaxWithdrawLog.setPlatformCode(accountType.getPlatform());
        //认证类型
        serviceLetaxWithdrawLog.setAuthType(serviceSign.getCurrentIdentity());
        serviceLetaxWithdrawLog.setMoney(money);
        serviceLetaxWithdrawLog.setReason(withdrawalApply.getReason());
        serviceLetaxWithdrawLog.setApplyRemark(withdrawalApply.getApplyRemark());
        serviceLetaxWithdrawLog.setRegisteredInfo(registeredInfo);
        serviceLetaxWithdrawLog.setStatus(LetaxWithdrawStatusEnum.APPLY.getCode());
        serviceLetaxWithdrawLog.setCreatedAt(DateTimeUtils.dateToLocalDateTime(nowDate));
        serviceLetaxWithdrawLog.setUpdatedAt(DateTimeUtils.dateToLocalDateTime(nowDate));

        serviceLetaxWithdrawLogService.save(serviceLetaxWithdrawLog);

        // 修改账户金额
        serviceAccountService
                .freezeBalance(accountType.getCode(), idCode, ProfitTypeEnum.ls_withdraw, money,
                        serviceLetaxWithdrawLog.getId(), cycleAddId);

        String content = "您已成功提交一笔【" + money + "】元的服务费申请，本次申请预计将在【" + DateTimeUtils
                .parseDateAsString(withdarwCycleAddParam.getEndAt(), "M月") +
                "15日】完成审核并发放到至您尾号为【" + bankNo.substring(bankNo.length() - 4) + "】的银行卡，如遇节假日顺延。";
//        if (CoverChargeEnum.ServiceAccountType.CUSTOMER_TYPE.getPlatform().
//
//                equals(accountType.getPlatform())) {
//            userMessageClient.sendDtServiceFeeMessage(idCode, "服务费申请通知"
//                    , content, true, true, true);
//        }

        return serviceLetaxWithdrawLog.getId();
    }

    /**
     * 个体提现申请取消
     *
     * @param idCode       idCode
     * @param platformCode 平台编号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int withdrawalApplyCancel(Integer idCode, String platformCode, Integer applyId,
                                     WithdrawalCancelEnum withdrawalCancelEnum) {
        return this
                .withdrawalApplyCancelNoTran(idCode, platformCode, applyId, withdrawalCancelEnum);
    }

    @Override
    public int withdrawalApplyCancelNoTran(Integer idCode, String platformCode, Integer applyId,
                                           WithdrawalCancelEnum withdrawalCancelEnum) {
        Integer accountType = null;
        if (CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getPlatform().equals(platformCode)) {
            accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getCode();
        }
        Assert.notNull(accountType, "账户类型不正确");

        ServiceAccount serviceAccount = serviceAccountService.getAccount(accountType, idCode);
        Integer accountId = serviceAccount.getId();
        List<ServiceLetaxWithdrawLog> letaxWithdrawLogList;

        ServiceWithdarwCycleAdd withdrawCycleAddResult;
        //当前时间
        Date nowDate = new Date();
        if (applyId == null) {
            withdrawCycleAddResult = serviceWithdarwCycleAddService.getOne(new QueryWrapper<>(
                    this.getWithdrawCycleAddParam(nowDate, accountId, idCode, false)));

            if (withdrawCycleAddResult == null) {
                return 0;
            }

            // 查询审核周期内待审核的提现申请
            ServiceLetaxWithdrawLog letaxWithdrawLogParam = new ServiceLetaxWithdrawLog();
            letaxWithdrawLogParam.setIdCode(idCode);
            letaxWithdrawLogParam.setPlatformCode(platformCode);
            letaxWithdrawLogParam.setStatus(LetaxWithdrawStatusEnum.APPLY.getCode());
            letaxWithdrawLogParam.setCycleAddId(withdrawCycleAddResult.getId());
            letaxWithdrawLogList = serviceLetaxWithdrawLogService
                    .list(new QueryWrapper<>(letaxWithdrawLogParam));
        } else {
            //用户自己取消
            ServiceLetaxWithdrawLog letaxWithdrawLog = serviceLetaxWithdrawLogService
                    .getById(applyId);
            Assert.notNull(letaxWithdrawLog, "没有查询到提现记录");
            Assert.isTrue(
                    LetaxWithdrawStatusEnum.APPLY.getCode().equals(letaxWithdrawLog.getStatus()),
                    "申请状态不正确");

            withdrawCycleAddResult = serviceWithdarwCycleAddService
                    .getById(letaxWithdrawLog.getCycleAddId());

            //只能取消本周期的提现
            ServiceWithdarwCycleAdd serviceWithdarwCycleAddData = this
                    .getWithdrawCycleAddParam(nowDate, accountId, idCode, false);
            Assert.isTrue(withdrawCycleAddResult.getStartAt()
                    .equals(serviceWithdarwCycleAddData.getStartAt()), "不是本周期的提现，无法取消");

            letaxWithdrawLogList = new ArrayList<>();
            letaxWithdrawLogList.add(letaxWithdrawLog);
        }
        if (CollectionUtil.isEmpty(letaxWithdrawLogList)) {
            return 0;
        }

        BigDecimal totalMoney = BigDecimal.ZERO;
        List<ServiceLetaxWithdrawLog> updateList = new ArrayList<>();
        List<WithdrawalApplyInfo> withdrawalApplyInfoList = new ArrayList<>();
        for (ServiceLetaxWithdrawLog letaxWithdrawLog : letaxWithdrawLogList) {
            totalMoney = totalMoney.add(letaxWithdrawLog.getMoney());

            ServiceLetaxWithdrawLog letaxWithdrawLogUp = new ServiceLetaxWithdrawLog();
            letaxWithdrawLogUp.setId(letaxWithdrawLog.getId());
            letaxWithdrawLogUp.setStatus(LetaxWithdrawStatusEnum.CANCEL.getCode());
            letaxWithdrawLogUp.setCancelRemark(withdrawalCancelEnum.getDesc());
            updateList.add(letaxWithdrawLogUp);

            WithdrawalApplyInfo withdrawalApplyInfo = new WithdrawalApplyInfo();
            withdrawalApplyInfo.setApplyMoney(letaxWithdrawLog.getMoney());
            withdrawalApplyInfo.setBizId(letaxWithdrawLog.getId());
            withdrawalApplyInfoList.add(withdrawalApplyInfo);
        }
        //更新提现申请表
        updateList.forEach(serviceLetaxWithdrawLog -> {

            boolean updateLog = serviceLetaxWithdrawLogService.updateById(serviceLetaxWithdrawLog);
            Assert.isTrue(updateLog, "提现记录变更失败");


        });

        //serviceLetaxWithdrawLogService.updateBatchById(updateList);

        // 提现周期表里的钱相应减少
        if (withdrawCycleAddResult != null) {
            BigDecimal total = withdrawCycleAddResult.getTotal().subtract(totalMoney);
            ServiceWithdarwCycleAdd serviceWithdarwCycleAddUp = new ServiceWithdarwCycleAdd();
            serviceWithdarwCycleAddUp.setId(withdrawCycleAddResult.getId());
            serviceWithdarwCycleAddUp.setTotal(total);
            serviceWithdarwCycleAddUp.setRatio(MoneyUtils.sumRatio(total));
            serviceWithdarwCycleAddService.updateById(serviceWithdarwCycleAddUp);
        }

        if (SignIdentityEnum.regist_soho.toString()
                .equals(letaxWithdrawLogList.get(0).getAuthType())) {
            this.updateOthersCycleAdd(nowDate, idCode, accountId, totalMoney);
        }

        //解冻
        serviceAccountService
                .unFreezeBalance(accountType, idCode, ProfitTypeEnum.ls_withdraw, totalMoney,
                        withdrawalApplyInfoList);

        return updateList.size();
    }

    /**
     * 个体提现申请修改
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdrawalApplyModify(WithdrawalModify withdrawalModify) {
        Integer idCode = withdrawalModify.getIdCode();
        String platformCode = withdrawalModify.getPlatformCode();

        Integer accountType = null;
        if (CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getPlatform().equals(platformCode)) {
            accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.getCode();
        }
        Assert.notNull(accountType, "账户类型不正确");

        ServiceAccount serviceAccount = serviceAccountService.getAccount(accountType, idCode);
        Integer accountId = serviceAccount.getId();

        Integer withdrawCycleAddId = null;
        Set<Integer> cycleAddIds = new HashSet<>();
        //当前时间
        Date nowDate = new Date();
        if (withdrawalModify.getWithdrawLogId() != null) {
            ServiceLetaxWithdrawLog letaxWithdrawLog = serviceLetaxWithdrawLogService
                    .getById(withdrawalModify.getWithdrawLogId());
            Assert.notNull(letaxWithdrawLog, "没有查询到相应的提现记录");
            Assert.isTrue(letaxWithdrawLog.getIdCode().equals(withdrawalModify.getIdCode()),
                    "提现记录的idCode不一致");
            String authType = letaxWithdrawLog.getAuthType();

            QueryWrapper<ServiceLetaxWithdrawLog> serviceLetaxWithdrawLogQueryWrapper = new QueryWrapper<>();
            serviceLetaxWithdrawLogQueryWrapper.select("distinct cycle_add_id");
            serviceLetaxWithdrawLogQueryWrapper.eq("auth_type", authType);
            serviceLetaxWithdrawLogQueryWrapper.eq("id_code", withdrawalModify.getIdCode());
            serviceLetaxWithdrawLogQueryWrapper.in("status",
                    LetaxWithdrawStatusEnum.PUTFAIL.getCode(),
                    LetaxWithdrawStatusEnum.APPLY.getCode(),
                    LetaxWithdrawStatusEnum.PASS.getCode());
            List<ServiceLetaxWithdrawLog> serviceLetaxWithdrawLogList = serviceLetaxWithdrawLogService
                    .list(serviceLetaxWithdrawLogQueryWrapper);

            for (ServiceLetaxWithdrawLog serviceLetaxWithdrawLog : serviceLetaxWithdrawLogList) {
                cycleAddIds.add(serviceLetaxWithdrawLog.getCycleAddId());
            }
        } else {
            ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                    .getOne(new QueryWrapper<>(
                            this.getWithdrawCycleAddParam(nowDate, accountId, idCode, false)));
            if (withdrawCycleAddResult != null) {
                withdrawCycleAddId = withdrawCycleAddResult.getId();
            }
        }

        List<ServiceLetaxWithdrawLog> letaxWithdrawLogList;
        if (CoverChargeEnum.CommonStatus.YES.getCode().equals(withdrawalModify.getFlag())) {
            //是否修改上个周期的记录打款失败的记录
            ServiceWithdarwCycleAdd withdrawCycleAddLast = serviceWithdarwCycleAddService
                    .getOne(new QueryWrapper<>(
                            this.getWithdrawCycleAddParam(nowDate, accountId, idCode, true)));
            if (withdrawCycleAddLast == null && withdrawCycleAddId == null) {
                return;
            }

            QueryWrapper<ServiceLetaxWithdrawLog> queryWrapper = this
                    .getLetaxWithdrawLogParamWrapper(idCode, platformCode,
                            withdrawalModify.getWithdrawLogId(),
                            withdrawalModify.getCurrentIdentity());
            if (withdrawCycleAddLast != null) {
                cycleAddIds.add(withdrawCycleAddLast.getId());
            }
            if (withdrawCycleAddId != null) {
                cycleAddIds.add(withdrawCycleAddId);
            }
            queryWrapper.in("cycle_add_id", cycleAddIds);
            letaxWithdrawLogList = serviceLetaxWithdrawLogService.list(queryWrapper);
        } else {
            // 查询审核周期内待审核的提现申请
            QueryWrapper<ServiceLetaxWithdrawLog> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id_code", withdrawalModify.getIdCode());
            if (withdrawalModify.getWithdrawLogId() != null) {
                queryWrapper.in("status",
                        LetaxWithdrawStatusEnum.PUTFAIL.getCode(),
                        LetaxWithdrawStatusEnum.APPLY.getCode(),
                        LetaxWithdrawStatusEnum.PASS.getCode());
            } else {
                queryWrapper.in("status",
                        LetaxWithdrawStatusEnum.APPLY.getCode(),
                        LetaxWithdrawStatusEnum.PASS.getCode());
            }

            if (withdrawCycleAddId != null) {
                cycleAddIds.add(withdrawCycleAddId);
            }
            if (CollectionUtils.isEmpty(cycleAddIds)) {
                return;
            }
            queryWrapper.in("cycle_add_id", cycleAddIds);
            letaxWithdrawLogList = serviceLetaxWithdrawLogService.list(queryWrapper);
        }

        // 身份信息
        SignIdentityEnum signIdentityEnum;
        String registeredInfo;
        if (withdrawalModify.getBankInfo() == null) {
            QueryWrapper<ServiceLetaxRegistered> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id_code", idCode);
            queryWrapper.eq("account_id", accountId);
            queryWrapper.ne("status", CoverChargeEnum.AuthStatus.END.getCode());
            //查找乐税信息
            ServiceLetaxRegistered serviceLetaxRegistered = serviceLetaxRegisteredService
                    .getOne(queryWrapper);
            Assert.notNull(serviceLetaxRegistered, "没有查询到乐税信息");
            Assert.isTrue(CoverChargeEnum.AuthStatus.PASS.getCode()
                    .equals(serviceLetaxRegistered.getStatus()), "乐税状态不正确");

            signIdentityEnum = SignIdentityEnum.regist_soho;
            registeredInfo = this.getRegisteredInfo(idCode, accountId);
        } else {
            signIdentityEnum = SignIdentityEnum.person;

            if (SignIdentityEnum.regist_soho.getCode()
                    .equals(withdrawalModify.getCurrentIdentity())) {
                List<RegisteredInfo> registeredInfoList = serviceLetaxRegisteredMapper
                        .queryRegisteredInfoList(idCode, accountId);
                RegisteredInfo registeredInfoNew;
                if (CollectionUtils.isEmpty(registeredInfoList)) {
                    registeredInfoNew = new RegisteredInfo();
                } else {
                    registeredInfoNew = registeredInfoList.get(0);
                }
                BankInfo bankInfo = withdrawalModify.getBankInfo();
                registeredInfoNew.setIdcardName(bankInfo.getIdcardName());
                registeredInfoNew.setIdcardNo(bankInfo.getIdcardNo());
                registeredInfoNew.setBankNo(bankInfo.getBankNo());
                registeredInfoNew.setBankName(bankInfo.getBankName());
                List<RegisteredInfo> registeredInfoListNew = new ArrayList<>();
                registeredInfoListNew.add(registeredInfoNew);
                registeredInfo = JSON.toJSONStringWithDateFormat(registeredInfoListNew,
                        DateTimeUtils.DEFAULT_DATE_TIME_FORMAT,
                        SerializerFeature.WriteDateUseDateFormat,
                        SerializerFeature.BrowserCompatible);
            } else {
                registeredInfo = JSON.toJSONStringWithDateFormat(withdrawalModify.getBankInfo(),
                        DateTimeUtils.DEFAULT_DATE_TIME_FORMAT,
                        SerializerFeature.WriteDateUseDateFormat,
                        SerializerFeature.BrowserCompatible);
            }

        }

        List<ServiceLetaxWithdrawLog> updateList = new ArrayList<>();
        for (ServiceLetaxWithdrawLog letaxWithdrawLog : letaxWithdrawLogList) {
            ServiceLetaxWithdrawLog letaxWithdrawLogUp = new ServiceLetaxWithdrawLog();
            letaxWithdrawLogUp.setId(letaxWithdrawLog.getId());
            letaxWithdrawLogUp.setRegisteredInfo(registeredInfo);
            if (withdrawalModify.getWithdrawLogId() != null) {
                // 提现发放失败-账户已修改
                if (LetaxWithdrawStatusEnum.PUTFAIL.getCode()
                        .equals(letaxWithdrawLog.getStatus())) {
                    letaxWithdrawLogUp.setStatus(LetaxWithdrawStatusEnum.PUTFAIL_MODIFY.getCode());
                }
            } else {
                letaxWithdrawLogUp.setAuthType(signIdentityEnum.toString());
            }
            letaxWithdrawLogUp.setUpdatedAt(LocalDateTime.now());
            updateList.add(letaxWithdrawLogUp);
        }
        if (!CollectionUtils.isEmpty(updateList)) {
            //修改个体提现申请
            //更新提现申请表
            updateList.forEach(serviceLetaxWithdrawLog -> {

                boolean updateLog = serviceLetaxWithdrawLogService.updateById(serviceLetaxWithdrawLog);
                Assert.isTrue(updateLog, "提现记录变更失败");


            });
            //serviceLetaxWithdrawLogService.updateBatchById(updateList);
        }
        if (withdrawalModify.getWithdrawLogId() != null && !CollectionUtils.isEmpty(cycleAddIds)) {
            List<ServiceWithdarwCycleAdd> serviceWithdarwCycleAdds = (List<ServiceWithdarwCycleAdd>) serviceWithdarwCycleAddService
                    .listByIds(cycleAddIds);
            List<ServiceWithdarwCycleAdd> serviceWithdarwCycleAddList = new ArrayList<>();
            for (ServiceWithdarwCycleAdd withdarwCycleAdd : serviceWithdarwCycleAdds) {
                ServiceWithdarwCycleAdd serviceWithdarwCycleAdd = new ServiceWithdarwCycleAdd();
                serviceWithdarwCycleAdd.setId(withdarwCycleAdd.getId());
                if (LetaxWithdrawStatusEnum.PUTFAIL.getCode()
                        .equals(withdarwCycleAdd.getWithdrawStatus())) {
                    serviceWithdarwCycleAdd
                            .setWithdrawStatus(LetaxWithdrawStatusEnum.PUTFAIL_MODIFY.getCode());
                }
                serviceWithdarwCycleAdd.setUpdatedAt(nowDate);
                serviceWithdarwCycleAddList.add(serviceWithdarwCycleAdd);
            }
            //更新提现申请表
            serviceWithdarwCycleAddList.forEach(serviceWithdarwCycleAdd -> {

                boolean updateLog = serviceWithdarwCycleAddService.updateById(serviceWithdarwCycleAdd);
                Assert.isTrue(updateLog, "提现记录变更失败");


            });
            //serviceWithdarwCycleAddService.updateBatchById(serviceWithdarwCycleAddList);
        }
    }

    @Override
    public void updateOthersCycleAdd(Date nowDate, Integer idCode, Integer accountId,
                                     BigDecimal subMoney) {
        List<ServiceLetaxRegisteredDto> serviceLetaxRegisteredDtoList = new ArrayList<>();
        serviceLetaxRegisteredDtoList.add(new ServiceLetaxRegisteredDto(idCode));
        Map<Integer, Boolean> numberCommonMap = serviceLetaxRegisteredService
                .getNumberCommon(serviceLetaxRegisteredDtoList);
        if (!(numberCommonMap.containsKey(idCode) && numberCommonMap.get(idCode))) {
            return;
        }

        BigDecimal cycleTotalMoney = this
                .getTotalCycleMoney(nowDate, SignIdentityEnum.regist_soho.toString(), accountId,
                        idCode);
        ServiceWithdarwCycleAdd withdarwCycleAddParam = this
                .getWithdrawCycleAddParam(nowDate, accountId, idCode, false);
        ServiceWithdarwCycleAdd withdrawCycleAddResult = serviceWithdarwCycleAddService
                .getOne(new QueryWrapper<>(withdarwCycleAddParam));
        boolean needUpdateOthers = false;
        if (withdrawCycleAddResult != null) {
            Assert.isTrue(CoverChargeEnum.CommonStatus.NO.getCode()
                    .equals(withdrawCycleAddResult.getWithdrawStatus()), "周期内已打款");
            if (cycleTotalMoney.compareTo(withdrawCycleAddResult.getTotal()) > 0) {
                //如果这个金额不一样，说明另外个平台的利率也需要修改
                needUpdateOthers = true;
            }
        }

        if (needUpdateOthers) {
            // 注册个体户需要查所有的平台（身份是注册个体户的）
            ServiceSign serviceSignParam = new ServiceSign();
            serviceSignParam.setIdCode(idCode);
            serviceSignParam.setCurrentIdentity(SignIdentityEnum.regist_soho.toString());
            List<ServiceSign> serviceSignList = serviceSignService
                    .list(new QueryWrapper<>(serviceSignParam));
            for (ServiceSign serviceSign : serviceSignList) {
                CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType
                        .getServiceAccountTypeByPlatform(serviceSign.getPlatformCode());
                if (accountType == null) {
                    throw new RuntimeException("平台编号：" + serviceSign.getPlatformCode() + "不正确");
                }
                ServiceAccount serviceAccount = serviceAccountService
                        .getAccount(accountType.getCode(), idCode);

                ServiceWithdarwCycleAdd serviceWithdarwCycleAddUp = new ServiceWithdarwCycleAdd();
                serviceWithdarwCycleAddUp
                        .setRatio(MoneyUtils.sumRatio(cycleTotalMoney.subtract(subMoney)));

                ServiceWithdarwCycleAdd serviceWithdarwCycleAddWhere = new ServiceWithdarwCycleAdd();
                serviceWithdarwCycleAddWhere.setAccountId(serviceAccount.getId());
                serviceWithdarwCycleAddWhere.setIdCode(idCode);
                serviceWithdarwCycleAddService.update(serviceWithdarwCycleAddUp,
                        new UpdateWrapper<>(serviceWithdarwCycleAddWhere));
            }
        }
    }

    /**
     * 获取乐税提现查询参数
     *
     * @param idCode          代理商编号
     * @param platformCode    平台编号
     * @param withdrawLogId   提现记录ID
     * @param currentIdentity 当前身份
     */
    private QueryWrapper<ServiceLetaxWithdrawLog> getLetaxWithdrawLogParamWrapper(Integer idCode,
                                                                                  String platformCode, Integer withdrawLogId, String currentIdentity) {
        QueryWrapper<ServiceLetaxWithdrawLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id_code", idCode);
        queryWrapper.eq("platform_code", platformCode);
        if (withdrawLogId != null) {
            queryWrapper.eq("status", LetaxWithdrawStatusEnum.PUTFAIL.getCode());
            queryWrapper.eq("auth_type", currentIdentity);
        } else {
            queryWrapper.in("status",
                    LetaxWithdrawStatusEnum.APPLY.getCode(),
                    LetaxWithdrawStatusEnum.PASS.getCode());
        }
        return queryWrapper;
    }

    /**
     * 获取提现周期参数(上个周期只取打款失败的)
     *
     * @param nowDate   当前时间-周期时间要跟提现记录时间一致
     * @param accountId 账户ID
     * @param idCode    idCode
     */
    private ServiceWithdarwCycleAdd getWithdrawCycleAddParam(Date nowDate, Integer accountId,
                                                             Integer idCode, boolean lastMonth) {
        //11号0点到次月10号24点
        //Date nowDate = new Date();
        String cycleDay = ConfigUtil.getConfig().getString("withdraw.cycle.day", "10");
        String startDateStr = DateUtil.format(nowDate, DateTimeUtils.MONTH_FORMAT) + "-" + (
                Integer.parseInt(cycleDay) + 1) + " 00:00:00";
        Date startDate = DateUtil.parse(startDateStr, DateTimeUtils.DEFAULT_DATE_TIME_FORMAT);
        if (lastMonth) {
            startDate = DateTimeUtils.addMonths(startDate, -1);
        }

        String endDateStr =
                DateUtil.format(nowDate, DateTimeUtils.MONTH_FORMAT) + "-" + cycleDay + " 23:59:59";
        Date endDate1 = DateUtil.parse(endDateStr, DateTimeUtils.DEFAULT_DATE_TIME_FORMAT);
        Date endDate = DateTimeUtils.addMonths(endDate1, 1);
        if (lastMonth) {
            endDate = DateTimeUtils.addMonths(endDate, -1);
        }

        if (nowDate.before(startDate)) {
            startDate = DateTimeUtils.addMonths(startDate, -1);
            endDate = endDate1;
        }
        ServiceWithdarwCycleAdd serviceWithdarwCycleAddParam = new ServiceWithdarwCycleAdd();
        serviceWithdarwCycleAddParam.setIdCode(idCode);
        serviceWithdarwCycleAddParam.setAccountId(accountId);
        serviceWithdarwCycleAddParam.setStartAt(startDate);
        serviceWithdarwCycleAddParam.setEndAt(endDate);
        if (lastMonth) {
            serviceWithdarwCycleAddParam
                    .setWithdrawStatus(LetaxWithdrawStatusEnum.PUTFAIL.getCode());
        }
        return serviceWithdarwCycleAddParam;
    }

    /**
     * 插入或者更新周期提现表
     *
     * @param nowDate   当前时间
     * @param accountId 账户ID
     * @param idCode    idCode
     */
    private Integer insertOrUpdateCycleAdd(Date nowDate,
                                           ServiceWithdarwCycleAdd withdrawCycleAddResult, BigDecimal cycleTotalMoney,
                                           Integer accountId, Integer idCode, BigDecimal money, boolean needUpdateOthers) {
        Integer cycleAddId;
        if (withdrawCycleAddResult != null) {
            BigDecimal total = withdrawCycleAddResult.getTotal().add(money);
            ServiceWithdarwCycleAdd serviceWithdarwCycleAddUp = new ServiceWithdarwCycleAdd();
            serviceWithdarwCycleAddUp.setId(withdrawCycleAddResult.getId());
            serviceWithdarwCycleAddUp.setTotal(total);
            serviceWithdarwCycleAddUp.setRatio(MoneyUtils.sumRatio(cycleTotalMoney.add(money)));
            serviceWithdarwCycleAddService.updateById(serviceWithdarwCycleAddUp);
            cycleAddId = withdrawCycleAddResult.getId();
        } else {
            //插入
            ServiceWithdarwCycleAdd serviceWithdarwCycleAddParam = this
                    .getWithdrawCycleAddParam(nowDate, accountId, idCode, false);
            serviceWithdarwCycleAddParam.setTotal(money);
            serviceWithdarwCycleAddParam.setRatio(MoneyUtils.sumRatio(cycleTotalMoney.add(money)));
            //未打款
            serviceWithdarwCycleAddParam
                    .setWithdrawStatus(CoverChargeEnum.CommonStatus.NO.getCode());
            serviceWithdarwCycleAddService.save(serviceWithdarwCycleAddParam);
            cycleAddId = serviceWithdarwCycleAddParam.getId();
        }

        if (needUpdateOthers) {
            // 注册个体户需要查所有的平台（身份是注册个体户的）
            ServiceSign serviceSignParam = new ServiceSign();
            serviceSignParam.setIdCode(idCode);
            serviceSignParam.setCurrentIdentity(SignIdentityEnum.regist_soho.toString());
            List<ServiceSign> serviceSignList = serviceSignService
                    .list(new QueryWrapper<>(serviceSignParam));
            for (ServiceSign serviceSign : serviceSignList) {
                CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType
                        .getServiceAccountTypeByPlatform(serviceSign.getPlatformCode());
                if (accountType == null) {
                    throw new RuntimeException("平台编号：" + serviceSign.getPlatformCode() + "不正确");
                }
                ServiceAccount serviceAccount = serviceAccountService
                        .getAccount(accountType.getCode(), idCode);

                ServiceWithdarwCycleAdd serviceWithdarwCycleAddUp = new ServiceWithdarwCycleAdd();
                serviceWithdarwCycleAddUp.setRatio(MoneyUtils.sumRatio(cycleTotalMoney.add(money)));

                ServiceWithdarwCycleAdd serviceWithdarwCycleAddWhere = new ServiceWithdarwCycleAdd();
                serviceWithdarwCycleAddWhere.setAccountId(serviceAccount.getId());
                serviceWithdarwCycleAddWhere.setIdCode(idCode);
                serviceWithdarwCycleAddService.update(serviceWithdarwCycleAddUp,
                        new UpdateWrapper<>(serviceWithdarwCycleAddWhere));
            }
        }
        return cycleAddId;
    }

    /**
     * 获取乐税信息
     *
     * @param idCode    idCode
     * @param accountId 账户ID
     */
    private String getRegisteredInfo(Integer idCode, Integer accountId) {
        List<RegisteredInfo> registeredInfoList = serviceLetaxRegisteredMapper
                .queryRegisteredInfoList(idCode, accountId);

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(new UserIdCode(idCode));
        }
        DepositoryAccount depositoryAccount;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.INTERNAL);
        } else {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.PING_AN);
        }
        if (depositoryAccount == null) {
            throw ApplicationException.error(ApplicationExceptionCode.DEP_ACCOUNT_NOT_OPEN);
        }
        List<DepositoryBankCard> bankCards = depositoryBankCardRepository
                .getByDepositoryAccountIdStatus(new UserIdCode(idCode), depositoryAccount.getDepositoryAccountId(),
                        List.of(BindStatus.SUCCESS));
        if (CollectionUtils.isEmpty(bankCards)) {
            throw ApplicationException.error(ApplicationExceptionCode.DEP_BAND_CARD_NOT_BOUND);
        }

        for (RegisteredInfo registeredInfo : registeredInfoList) {
            registeredInfo.setBankName(bankCards.get(0).getBankName());
            registeredInfo.setBankNo(bankCards.get(0).getCardNo());
            registeredInfo.setDepositoryChannel(depositoryAccount.getDepositoryChannel().getInnerVal());
        }


        return JSON.toJSONStringWithDateFormat(registeredInfoList,
                DateTimeUtils.DEFAULT_DATE_TIME_FORMAT,
                SerializerFeature.WriteDateUseDateFormat, SerializerFeature.BrowserCompatible);
    }

    /**
     * 个体提现申请理由修改
     *
     * @param idCode          代理id
     * @param platformCode    平台
     * @param withdrawalApply withdrawalApply
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer updateApplyReason(Integer idCode, String platformCode,
                                     WithdrawalApply withdrawalApply) {
        //乐税提现
        ServiceLetaxWithdrawLog letaxWithdrawLogParam = new ServiceLetaxWithdrawLog();
        letaxWithdrawLogParam.setId(withdrawalApply.getId());
        ServiceLetaxWithdrawLog serviceLetaxWithdrawLog = serviceLetaxWithdrawLogService
                .getOne(new QueryWrapper<>(letaxWithdrawLogParam));

        //如果记录为空或者提现idCode不相等
        if (Objects.isNull(serviceLetaxWithdrawLog) || !serviceLetaxWithdrawLog.getIdCode()
                .equals(idCode)) {
            //自认证提现判断
            ServiceSelfCertificationWithdraw selfCertificationWithdrawUp = new ServiceSelfCertificationWithdraw();
            selfCertificationWithdrawUp.setId(withdrawalApply.getId());
            ServiceSelfCertificationWithdraw serviceSelfCertificationWithdraw = serviceSelfCertificationWithdrawService
                    .getOne(new QueryWrapper<>(selfCertificationWithdrawUp));
            Assert.isTrue(Objects.nonNull(serviceSelfCertificationWithdraw),
                    "不存在当前提现记录：" + withdrawalApply.getId());
            Assert.isTrue(serviceSelfCertificationWithdraw.getIdCode().equals(idCode),
                    "当前提现记录不是本人提现" + withdrawalApply.getId());
            Assert.isTrue(serviceSelfCertificationWithdraw.getPlatformCode().equals(platformCode),
                    "当前提现记录平台不正确" + withdrawalApply.getId());

            //更新数据准备
            selfCertificationWithdrawUp.setRemark("修改申请理由");
            selfCertificationWithdrawUp.setReason(0);
            selfCertificationWithdrawUp.setReasonNew(withdrawalApply.getReason());
            selfCertificationWithdrawUp.setUpdatedAt(LocalDateTime.now());
            selfCertificationServiceImpl.updateApplyReasonDb(selfCertificationWithdrawUp);
            return withdrawalApply.getId();
        }

        //乐税提现判断
        Assert.isTrue(serviceLetaxWithdrawLog.getPlatformCode().equals(platformCode),
                "当前提现记录平台不正确" + withdrawalApply.getId());

        letaxWithdrawLogParam.setUpdatedAt(LocalDateTime.now());
        letaxWithdrawLogParam.setRemark("修改申请理由");
        letaxWithdrawLogParam.setReason(withdrawalApply.getReason());
        updateAppleReasonDb(letaxWithdrawLogParam);

        return withdrawalApply.getId();
    }

    /**
     * 个体提现申请理由修改(自认证有用到这个方法)
     *
     * @param letaxWithdrawLogParam letaxWithdrawLogParam
     */
    public void updateAppleReasonDb(ServiceLetaxWithdrawLog letaxWithdrawLogParam) {
        serviceLetaxWithdrawLogService.updateById(letaxWithdrawLogParam);
    }

    @Override
    public void signSuccessToNoticeMember(UserIdCode idCode, LocalDateTime checkTime, Sign sign) {
        try {
            SelfCertificationDto selfCertificationDto = new SelfCertificationDto();
            selfCertificationDto.setIdCode(((Long) idCode.getValue()).intValue());
            selfCertificationDto.setPlatformCode("DT");
            selfCertificationDto.setCheckAt(checkTime);
            selfCertificationDto.setBeforeIdentity(sign.getBeforeIdentity().getVal());
            selfCertificationDto.setCurrentIdentity(sign.getCurrentIdentity().getVal());
            noticeMemberProvider.signSuccessToNoticeMember(selfCertificationDto);
        } catch (Exception e) {
            sign.change(0);
            signRepository.update(sign.getSignId(), sign);
            log.error("signSuccessToNoticeMember error", e);
            throw new BizException("亲，系统有点繁忙，请稍后再来");
        }
    }

    @Override
    public void modifyRegisteredWithdrawalRecords(UserIdCode idCode, IdentityType currentIdentity) {
        WithdrawalModify withdrawalModify = new WithdrawalModify();
        withdrawalModify.setIdCode(((Long) idCode.getValue()).intValue());
        withdrawalModify.setPlatformCode("DT");
        withdrawalModify.setCurrentIdentity(currentIdentity.getVal());
        withdrawalModify.setFlag(0);
        withdrawalProvider.modifyWithdrawalApply(withdrawalModify);
    }

    @Override
    public void modifyRegisteredWithdrawalRecords(UserIdCode idCode, IdentityType currentIdentity,
                                                  LetaxWithdrawId letaxWithdrawId, BankInfo bankInfo) {
        WithdrawalModify withdrawalModify = new WithdrawalModify();
        withdrawalModify.setIdCode(((Long) idCode.getValue()).intValue());
        withdrawalModify.setPlatformCode("DT");
        withdrawalModify.setCurrentIdentity(currentIdentity.getVal());
        withdrawalModify.setFlag(currentIdentity == IdentityType.PERSON ? 1 : 0);
        withdrawalModify.setWithdrawLogId((int) letaxWithdrawId.getValue());
        withdrawalModify.setBankInfo(bankInfo);
        withdrawalProvider.modifyWithdrawalApply(withdrawalModify);
    }

    @Override
    @Transactional
    public void register(com.tengju.user.domain.model.user.UserIdCode idCode, AccountId accountId,
                         LetaxAccount letaxAccount, LetaxSnapshot snapshot) {

        //是否向java发送数据请求
        boolean hasUpdate = false;
        boolean registeredStatus = false;

        Sign sign;
        if (letaxAccount.getStatus() != UN_APPLY) {
            registeredStatus = true;
        }

        LetaxSnapshot exist = letaxSnapshotRepository.find(letaxAccount.getLetaxAccountId());
        LetaxSnapshotId snapshotId;
        if (exist != null) {//更新
            snapshotId = exist.getLetaxSnapshotId();
            letaxSnapshotRepository.update(snapshotId, snapshot);
        } else {//新增
            snapshotId = letaxSnapshotRepository.save(snapshot);
        }

        if (snapshotId != null) {
            letaxAccount.check();

            //根据乐税状态
            switch (snapshot.getStateCode()) {
                case "00"://正常
                    if (StringUtils.isEmpty(snapshot.getIdCardNo())) {//身份证为空
                        throw new BizException("身份证为空");
                    }
                    //身份证匹配信息
                    if (snapshot.getIdCardNo() != null
                            && snapshot.getIdCardNo()
                            .equalsIgnoreCase(letaxAccount.getIdCardNo())) {
                        letaxAccount.finish(); //注册完成
                        hasUpdate = true;
                    } else {
                        letaxAccount.failToRelate("收款账户信息与注册个体户工商法人信息不一致，请修改收款账户信息"); //关联失败
                    }
                    break;
                case "01"://申请中
                    letaxAccount.apply(); //申请中
                    break;
                case "03"://注销
                    letaxAccount.terminate(null); //终止
                    break;
                case "02"://注册中
                case "04"://待审核
                    letaxAccount.register(); //注册中
                    break;
                default://中心企业驳回和运营端驳回
                    if ("04".equals(snapshot.getRejectType()) || "05"
                            .equals(snapshot.getRejectType())) {
                        letaxAccount.terminate(snapshot.getRejectReason()); //终止
                    } else {
                        letaxAccount.failToRegister(snapshot.getRejectReason()); //注册失败
                    }
            }

            //获取签约记录信息
            sign = signRepository.find(idCode);
            //终止
            if (letaxAccount.isTerminated()) {
                terminate(idCode, accountId, sign);
            }

            //更新注册信息
            letaxRepository.update(letaxAccount.getLetaxAccountId(), letaxAccount);
        } else {
            log.error("商户信息存入错误");
            throw new BizException("商户信息存入错误");
        }

        //只有初次升级且个体户身份证成功后才能调用java和对个人进行解绑
        if (sign != null && sign.getBeforeIdentity() == PERSON
                && sign.getCurrentIdentity() == REGISTER_SOHO && hasUpdate && registeredStatus) {
            // 调用java修改收款账户信息
            try {
                modifyRegisteredWithdrawalRecords(new UserIdCode(idCode.getValue()), PERSON);
            } catch (Exception e) {
                log.error("modifyRegisteredWithdrawalRecords error", e);
                throw new BizException("注册信息回调失败");
            }
        }
    }

    public void terminate(com.tengju.user.domain.model.user.UserIdCode idCode, AccountId accountId,
                          Sign sign) {
        int withdrawCount = letaxWithdrawRepository.count(idCode, accountId,
                Arrays.asList(LetaxWithdrawStatus.APPLIED,
                        LetaxWithdrawStatus.APPROVED,
                        LetaxWithdrawStatus.SEND_FAILED,
                        LetaxWithdrawStatus.ACCOUNT_CHANGED),
                REGISTER_SOHO
        );
        if (withdrawCount > 0) {
            throw new BizException(idCode + "用户存在存在提现流程，不可终止,请取消后再操作");
        }

        //如果之前的身份为个人，则是升级来的
        if (sign.getBeforeIdentity() == PERSON) {
            //判断个人有没有签约
            int logCount = signLogRepository.count(idCode, "sign",
                    PERSON.getVal());

            IdentityType historyIdentity = PERSON;
            String isSigned = "no";
            String isView = "FIRST";

            if (logCount > 0) {
                historyIdentity = null;
                isSigned = "yes";
                isView = "NOT_FIRST";
            }

            sign.change(NO_IDENTITY, PERSON, historyIdentity, isSigned, isView);
            signRepository.update(sign.getSignId(), sign);

            //启用个人信息最后一条创建的
            BankCard lastBankCard = bankCardRepository.findLastOne(idCode, BankCardStatus.UNLINK);
            if (lastBankCard != null) {
                lastBankCard.enable();
                bankCardRepository.update(lastBankCard.getBankCardId(), lastBankCard);
            }
        } else {
            //更新签约记录表
            sign.changeSign2No(REGISTER_SOHO, NO_IDENTITY, null);
            signRepository.update(sign.getSignId(), sign);
            //TODO null覆盖检查
        }
        //插入签约记录表
        SignLog log = new SignLog(idCode,
                "终止",
                REGISTER_SOHO,
                NO_IDENTITY,
                "乐税的第三方回调操作"
        );
        signLogRepository.save(log);
    }

    @Override
    public void idcardAndBank(UserIdCode idCode,
                              IdCardNo idCardNo, String idCardName, String bankNo) {

//        if (!(bankNo.matches("^\\d+$"))) {
//            throw new BizException("银行卡格式有误，请检查是否包含空格或除数字以外的其它字符");
//        }

        //个人收款账户中
        int bankCardCount = bankCardRepository
                .count(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()),
                        idCardNo, BankCardStatus.ENABLE);
        if (bankCardCount > 0) {
            throw new BizException("身份证已被其他个人账号使用，请更换");
        }

        //注册信息表中
        int letaxAccountCount = letaxRepository
                .count(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()),
                        idCardNo, LetaxStatus.TERMINATED);
        if (letaxAccountCount > 0) {
            throw new BizException("身份证已关联其他个体户，请更换");
        }

        // 第三方银行卡身份校验
        userInfoService.checkUserInfoForSign(idCardName, idCardNo.getValue());
    }
}
